#!/usr/bin/env python
#coding=utf-8
import urllib2
import time
import cookielib

class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):    
    def http_error_default(self, req, fp, code, msg, headers): 
        result = urllib2.HTTPError(req.get_full_url(), code, msg, headers, fp)       
        result.status = code                                   
        return result 

def initlog(logfile=''):
    import logging    
    logger = logging.getLogger()
    if logfile:
        hdlr = logging.FileHandler(logfile)
    else:
        hdlr = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
    hdlr.setFormatter(formatter)
    logger.addHandler(hdlr)
    #logger.setLevel(logging.NOTSET)
    logger.setLevel(logging.INFO)
    return logger

class Web:
    def __init__(self, proxy='', logfile='', interval_time=180, times=3):
        import socket        
        timeout = 30 #seconds
        socket.setdefaulttimeout(timeout)
        
        self.cj = cookielib.CookieJar()
        if proxy:
            self.__opener = urllib2.build_opener(urllib2.ProxyHandler({'http':proxy}), urllib2.HTTPCookieProcessor(self.cj), DefaultErrorHandler())
        else:
            self.__opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj), DefaultErrorHandler())

        self.headers = {
            'User-Agent'        : 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; CIBA; MAXTHON 2.0)',
            'Accept'            : '*/*',
            'Accept-Language'   : 'zh-cn',
            'Content-Type'      : 'application/x-www-form-urlencoded',
            'UA-CPU'            : 'x86',
            'Connection'        : 'Keep-Alive',
            'Cache-Control'     : 'no-cache',
            'Accept-Encoding'   : '*/*',
        }
        try:
            self.headers['host'] = self.host
        except AttributeError:
            pass
        self.logger = initlog(logfile)
        self.interval_time = interval_time        
        self.times = times
        self.isSet = False#停止标志
        
    def fetchData(self, referer, url, data=None):
        self.logger.debug('===========\n%s\n%s=============' % (url, data))        
        self.headers['referer'] = referer
        request = urllib2.Request(url=url, data=data, headers=self.headers)
        f = self.__myopen(self.__opener, request)
        return f
    def sleepWithSet(self, seconds):
        for i in range(seconds):
            if not self.isSet: 
                time.sleep(1)
            else:
                break
        return
        
    def __myopen(self, opener, request): 
        times = self.times
        while times > 0:
            if not self.isSet:
                try:
                    response = opener.open(request)
                    if response.code != 200:
                        self.logger.info(u'远程服务器未正常返回，响应码：%s' % response.code)
                        times -= 1
                        if times > 0:
                            self.logger.info(u'%s秒后再次尝试' % self.interval_time)
                            self.sleepWithSet(self.interval_time)  
                        else:
                            self.logger.info(u'网络失败')   
                        continue
                except IOError, e:
                    if hasattr(e, 'reason'):
                        self.logger.info(u'访问远程服务器失败，原因：%s' % e.reason)         
                    elif hasattr(e, 'code'):
                        self.logger.info(u'请求不能满足远程服务器，错误代码：%s' % e.code)                  
                    times -= 1
                    if times > 0:
                        self.logger.info(u'%s秒后再次尝试' % self.interval_time)
                        self.sleepWithSet(self.interval_time) 
                    else:
                        self.logger.info(u'网络失败')
                    continue
                else:
                    self.cookies = self.cj.make_cookies(response, request)
                    return response  
            else:
                return False
        else:
            return False   

